import math
import os
from datetime import datetime
import docx
import pandas as pd
from docx import Document
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT, WD_LINE_SPACING
from docx.oxml.ns import qn
from docx.shared import Pt, RGBColor


def get_font_info(run):
    """获取文本运行的字体信息"""
    font = run.font
    return {
        "name": font.name,
        "size": font.size.pt if font.size else None,
        "bold": font.bold,
        "italic": font.italic,
        "underline": font.underline,
        "color": f"#{font.color.rgb}" if font.color.rgb else None,
        "strike": font.strike,
        "all_caps": font.all_caps
    }

def hex_to_rgb(hex_color):
    # 去掉#号
    hex_without_hash = hex_color.lstrip('#')

    # 分割成R, G, B部分
    r_str = hex_without_hash[0:2]
    g_str = hex_without_hash[2:4]
    b_str = hex_without_hash[4:6]

    # 转换为十进制
    r = int(r_str, 16)
    g = int(g_str, 16)
    b = int(b_str, 16)

    # 创建RGBColor对象
    rgb_color =RGBColor(r, g, b)

    return rgb_color

def get_paragraph_format(paragraph):
    """获取段落格式信息"""
    format = paragraph.paragraph_format
    alignment_map = {
        0: "left",
        1: "center",
        2: "right",
        3: "justify",
        4: "distributed"
    }
    return {
        "alignment": alignment_map.get(format.alignment, "unknown"),
        "line_spacing": format.line_spacing,
        "space_before": format.space_before.pt if format.space_before else 0,
        "space_after": format.space_after.pt if format.space_after else 0,
        "indentation": {
            "first_line": format.first_line_indent.pt if format.first_line_indent else 0,
            "left": format.left_indent.pt if format.left_indent else 0
        }
    }

def parse_text(paragraph):
    """解析段落中的文本和样式"""
    text_runs = []
    for run in paragraph.runs:
        text_runs.append({
            "text": run.text,
            "font": get_font_info(run)
        })
    return text_runs

def parse_table(table):
    """解析表格内容和样式"""
    table_data = []
    for row_idx, row in enumerate(table.rows):
        row_data = []
        for cell_idx, cell in enumerate(row.cells):
            cell_text = ""
            cell_runs = []

            # 合并单元格的处理
                        if cell._element.xpath('.//w:tcPr/w:vMerge'):
                vmerge = cell._element.xpath('.//w:tcPr/w:vMerge')[0].get(
                    "{http://schemas.openxmlformats.org/wordprocessingml/2006/main}val")
                if vmerge == "continue":
                    cell_text = "[合并单元格]"
            else:
                for paragraph in cell.paragraphs:
                    cell_text += paragraph.text + "\n"
                    for run in paragraph.runs:
                        cell_runs.append({
                            "text": run.text,
                            "font": get_font_info(run),
                            "format": get_paragraph_format(paragraph)
                        })
            row_data.append({
                "text": cell_text.rstrip(),
                "runs": cell_runs,
                "style": {
                    "vertical_alignment": str(cell.vertical_alignment),
                    "width": cell.width.pt if cell.width else NoNone
                }
            })
        table_data.append(row_data)
    return table_data

def read_word_document(file_path):
    """读取Word文档并提取内容和样式"""
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"文件不存在: {file_path}")

    doc = docx.Document(file_path)
    document_data = {
        "metadata": {
            "title": doc.core_properties.title,
            "author": doc.core_properties.author,
            "created": str(doc.core_properties.created),
            "modified": str(doc.core_properties.modified),
            "words_count": sum(len(p.text.split()) for p in doc.paragraphs)
        },
        "elements": []
    }

    for element in doc.element.body:
        # 处理段落
        if element.tag.endswith('p'):
            p_idx = len([e for e in document_data["elements"] if e["type"] == "paragraph"])
            paragraph = doc.paragraphs[p_idx]

            document_data["elements"].append({
                "type": "paragraph",
                "style": {
                    "name": paragraph.style.name,
                    "format": get_paragraph_format(paragraph)
                },
                "text_runs": parse_text(paragraph),
                "raw_text": paragraph.text
            })

        # 处理表格

                        elif element.tag.endswith('tbl'):
            t_idx = len([e for e in document_data["elements"] if e["type"] == "table"])
            table = doc.tables[t_idx]

            document_data["elements"].append({
                "type": "table",
                "style": {
                    "name": table.style.name
                },
                "rows": len(table.rows),
                "columns": len(table.columns),
                "data": parse_table(table)
            })
            break;

    return document_data

def set_paragraph_format(paragraph,style):
    """设置段落格式"""
    alignment=style['alignment']
    if alignment=='left':
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
    elif alignment=='right':
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.RIGHT
    elif alignment=='center':
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
    elif alignment=='justify':
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.JUSTIFY
    elif alignment=='distributed':
       paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.DISTRIBUTE
    else:
        paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.LEFT
    paragraph_format = paragraph.paragraph_format
    line_spacing=style['line_spacing']
    paragraph_format.line_spacing_rule = WD_LINE_SPACING.ONE_POINT_FIVE if line_spacing == 1.5 else \
        WD_LINE_SPACING.EXACTLY if line_spacing == 1.0 else \
            WD_LINE_SPACING.MULTIPLE
    paragraph_format.line_spacing = style['line_spacing']
    paragraph_format.space_before = Pt(style['space_before'])
    paragraph_format.space_after = Pt(style['space_after'])
    return paragraph

def get_indices(headers,value):
    # 创建记录所有索引的字典
    field_to_indices = {}
    for index, field in enumerate(headers):
        if field not in field_to_indices:
            field_to_indices[field] = []
        field_to_indices[field].append(index)

    return field_to_indices.get(value, [])

def set_run_format(run, text_runs):
    """设置文本格式"""
    font = run.font
    name=text_runs['font']['name']
    if name:
        font.name = name
    else:
        font.name = "SimSun"
    size=text_runs['font']['size']
    if size:
        font.size = Pt(size)
    font.bold = text_runs['font']['bold']
    font.italic = text_runs['font']['italic']
    if text_runs['font']['color']:
        font.color.rgb = hex_to_rgb(text_runs['font']['color'])
    else:
        font.color.rgb=hex_to_rgb('#000000')
    return run
def write_word(template,excel_file,config,word_file=None):
    """
    将Excel文件内容转换为Word文档
    返回:
    str: 生成的Word文件路径
    """

    # 检查文件是否存在
    if not os.path.exists(excel_file):
        raise FileNotFoundError(f"Excel文件不存在: {excel_file}")

    # 读取Excel文件
        try:
        df = pd.read_excel(excel_file, sheet_name=0)
    except Exception as e:
        raise Exception(f"读取Excel文件失败: {str(e)}")
    # 如果未指定输出文件名，自动生成
    if not word_file:
        base_name = os.path.splitext(os.path.basename(excel_file))[0]
        word_file = f"{base_name}_转换后_{datetime.now().strftime('%Y%m%d%H%M%S')}.docx"

    # 读取word模板样式
    document_data = read_word_document(template)
    if document_data['elements'][-1]['type']!='table':
        print("word模板里没有找到表格")
        return
    # 创建Word文档
    print(document_data['elements'])
    doc = Document()

    # 修改默认样式
    style = doc.styles['Normal']

    # 设置中文字体
    style.font.name = 'SimSun'
    r = style.element.rPr.rFonts
    r.set(qn('w:eastAsia'), '宋体')

    # 设置英文字体
    r.set(qn('w:ascii'), 'Arial')
    r.set(qn('w:hAnsi'), 'Arial')

     #测试用例excel表头
    headers = [str(col) for col in df.columns]
    print(f"测试用例excel的header={headers}")
    # 添加数据行
    for row_idx, row in enumerate(df.itertuples(index=False), start=1):
        # for col_idx, value in enumerate(row):
        # 添加标题还是用例
        print(f"第{row_idx}行的内容row={row}")
        # index=get_indices(headers,'测试用例_级别')
        case_depth=row[0]
        length_depth=len(case_depth)
        if length_depth>len(document_data['elements'][:-1]):
            length_depth=len(document_data['elements'][:-1])
        case_title=row[1]
        case_no=row[2]
        case_name=row[3]
        case_condtion=row[4]
        case_step=row[5]
        case_result=row[6]
        case_priority=row[7]
        case_content=row[8]

        if isinstance(case_title, float) and math.isnan(case_title) or isinstance(case_name, str):
            tables = document_data['elements'][-1]

            # 创建表格
            table_rows=tables['rows']
            table_columns=tables['columns']
            table = doc.add_table(rows=table_rows, cols=table_columns)
            table.style = 'Table Grid'

            # 添加数据行
                        for table_idx in range(table_rows):
                row_cells = table.rows[table_idx].cells
                cell = row_cells[0]
                # 清空单元格中的默认段落
                # cell._element.clear_content()
                cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER
                paragraph = cell.paragraphs[0]

                value_prefix=tables["data"][table_idx][0]["runs"][0]["text"]
                run = paragraph.add_run(str(value_prefix) if pd.notna(vaue_prefix) else "")

                #设置字体样式
                # 清除标题样式中可能存在的默认字体设置
                styles = tables["data"][table_idx][0]["runs"][0]
                font = styles['font']
                # 设置西文字体
                if font['name']:
                    run.font.name = font['name']
                    # 设置中文字体
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), font['name'])
                else:
                    run.font.name = '宋体'
                    # 设置中文字体
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
                # 设置字体大小
                if font['size']:
                    run.font.size = Pt(font['size'])
                set_run_format(run, tables["data"][table_idx][0]["runs"][0])
                set_paragraph_format(paragraph, tables["data"][table_idx][0]["runs"][0]["format"])

                paragraph.add_run(str("\n"))
                index=get_indices(headers,config[value_prefix])[0]
                value_content=row[index]
                value=str(value_content) if pd.notna(value_content) else ""

                run = paragraph.add_run(str(value))

                styles = tables["data"][table_idx][0]["runs"][1]
                font = styles['font']
                # 设置西文字体
                if font['name']:
                    run.font.name = font['name']
                    # 设置中文字体
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), font['name'])
                              else:
                    run.font.name = '宋体'
                    # 设置中文字体
                    run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
                # 设置字体大小
                if font['size']:
                    run.font.size = Pt(font['size'])
                set_run_format(run,tables["data"][table_idx][0]["runs"][1])

                set_paragraph_format(paragraph, tables["data"][table_idx][0]["runs"][1]["format"])
            # 添加空白段落
            paragraph = doc.add_paragraph()
        else:
            styles = document_data['elements'][length_depth - 1]
            head_level=styles['style']['name']
            title = doc.add_heading(level=int(str.replace(head_level,"Heading ","")))
            # 清除标题样式中可能存在的默认字体设置
            title.style._element.rPr.rFonts.clear()

            font=styles['text_runs'][0]['font']
            # 设置西文字体
            if font['name']:
                title.style.font.name = font['name']
       # 设置中文字体
                title.style._element.rPr.rFonts.set(qn('w:eastAsia'), font['name'])
            else:
                title.style.font.name = '宋体'
                # 设置中文字体
                title.style._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
            # 设置字体大小
            if font['size']:
                title.style.font.size = Pt(font['size'])
            title_run = title.add_run(case_title)
            set_run_format(title_run,styles['text_runs'][0])
            set_paragraph_format(title,styles['style']['format'])
    # 保存Word文档
    try:
        doc.save(word_file)
        print(f"成功生成Word文档: {word_file}")
        return word_file
    except Exception as e:
        raise Exception(f"保存Word文档失败: {str(e)}")

if __name__ == "__main__":
    config={
        "测试目的":"测试用例_名称",
        "预置条件":"测试用例_预置条件",
        "测试步骤":"测试用例_测试步骤",
        "预期结果": "测试用例_预期结果",
        "测试结果": "测试用例_预期结果",
        "测试说明": "测试用例_备注",
        "测试编号":"测试用例_编号"
    }
    write_word("测试用例word.docx","测试用例excel.xls",config)
        